#include "tcp_service.hpp"
#include "event_loop.hpp"
#include "event_trace.hpp"
#include "event_error.hpp"
#include <error.h>

using namespace event_framework;

bool TcpService::Init()
{
    int fd = socket.Create(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
    if (fd < 0)
    {
        EVENT_TRACE_ERROR("[TcpService::Init] create socket failed with err=" << error);
        if (eventCallback.exceptionCallback)
        {
            eventCallback.exceptionCallback(socket, EVENT_ERR_SOCK_CREATE);
        }
        return false;
    }
    return true;
}

bool TcpService::Fini()
{
    // server
    if (acceptor != nullptr)
    {
        ASSERT(connector != nullptr);
        loop.Accept([this]()->void
        {
            acceptor->Fini();
            CloseAllConnection();
        });
    }
    // client
    if (connector != nullptr)
    {
        ASSERT(acceptor != nullptr);
        loop.Accept([this]()->void
        {
            connector->Fini();
        });
    }
    // parent
    NetService::Fini();
    return true;
}
bool TcpService::Listen(int backlog)
{
    ASSERT(connector == nullptr);
    acceptor = std::unique_ptr<Acceptor>(new Acceptor(loop, socket));
    ASSERT(acceptor != nullptr);
    if (acceptor->Avaliable())
    {
        loop.Accept([this, backlog]()->void
        {
            acceptor->SetNewConnCallback(
                std::bind(&TcpService::NewConnection, this, std::placeholders::_1));
            acceptor->Listen(backlog);
        });
        return true;
    }
    EVENT_TRACE_ERROR("[TcpService::Listen] acceptor is disabled");
    return false;
}
bool TcpService::Connect(const EndPoint& peer)
{
    ASSERT(acceptor == nullptr);
    connector = std::unique_ptr<Connector>(new Connector(loop, socket));
    ASSERT(connector != nullptr);
    if (connector->Avaliable())
    {
        loop.Accept([this, &peer]()->void
        {
            connector->SetNewConnCallback(
                std::bind(&TcpService::NewConnection, this, std::placeholders::_1));
            connector->Connect(peer);
        });
        return true;
    }
    EVENT_TRACE_ERROR("[TcpService::Connect] connector is disabled");
    return false;
}
void TcpService::NewConnection(Socket& socket)
{
    int sockfd = socket.GetFd();
    if (connMgr.HasConnection(sockfd))
    {
        EVENT_TRACE_ERROR("[TcpService::NewConnection] no connection for sockfd=" << sockfd);
        return;
    }
    auto conn = std::make_shared<Connection>(loop, socket);
    connMgr.AddConnection(sockfd, conn);
    ASSERT(eventCallback != nullptr);
    EventLoop* innerloop = &loop;
    if (pool != nullptr)
    {
        innerloop = &(pool->GetProperLoop());
    }
    // execute asynchronously callback in eventloop is for quickly responding connection request due to callback maybe take long time
    innerloop->Accept([this, &socket, conn]()->void
    {
        ASSERT(newConnCallback != nullptr);
        newConnCallback(socket);
        conn->Open(eventCallback);
    });
}